// ssh_node.rs
//
//
//
use ssh2::{Error, Session};
use std::fs;
use std::io::prelude::*;
use std::net::TcpStream;
use std::path::Path;

pub struct SSHNode {
    pub host: String,
    s: ssh2::Session,
}

impl SSHNode {
    //pub fn new(host: String) -> Self {
    //    if host.contains(":") {}

    //    SSHNode {
    //        host: host,
    //        s: Session::new().unwrap(),
    //    }
    //}
    pub fn new(host: &str, user: &str, passwd: Option<String>) -> Self {
        let mut h: String = String::from(host);
        if !host.contains(":") {
            h = format!("{}:22", host);
        }
        let mut s = Session::new().unwrap();
        let tcp = TcpStream::connect(&h).unwrap();
        s.set_tcp_stream(tcp);
        s.handshake().unwrap();

        match passwd {
            Some(passwd) => s.userauth_password(user, &passwd),
            None => s.userauth_agent(user),
        };

        SSHNode {
            host: host.to_string(),
            s: s,
        }
    }

    pub fn init(&mut self, username: &str, passwd: Option<String>) -> Result<(), Error> {
        let mut h: String = String::from(&self.host);
        if !self.host.contains(":") {
            h = format!("{}:22", &self.host);
        }
        let tcp = TcpStream::connect(&h).unwrap();
        self.s.set_tcp_stream(tcp);
        self.s.handshake().unwrap();

        match passwd {
            Some(passwd) => self.s.userauth_password(username, &passwd),
            None => self.s.userauth_agent(username),
        }
    }

    pub fn exec(&self, cmd: &str) -> Result<String, Error> {
        let mut channel = self.s.channel_session().unwrap();
        channel.exec(cmd).unwrap();
        let mut output = String::new();
        channel.read_to_string(&mut output).unwrap();
        channel.wait_close().unwrap();

        match channel.exit_status() {
            Err(err) => Err(err),
            Ok(_) => Ok(output),
        }
    }

    // upload src to tgt
    pub fn upload(&self, _src: &str, tgt: &str) -> Result<(), Error> {
        let l = fs::metadata(_src).unwrap().len();
        let mut remote_file = self
            .s
            .scp_send(Path::new(tgt), 0o644, l as u64, None)
            .unwrap();
        let mut buffer = [0u8; 4096];
        let mut file = fs::File::open(_src).unwrap();

        loop {
            let l = file.read(&mut buffer).unwrap();
            if l == 0 {
                break;
            }
            if l > 0 {
                remote_file.write(&buffer[..l]).unwrap();
            }
        }

        remote_file.close()
    }
}
